package edu.siu.math.egut.util;

import java.io.Serializable;
import java.util.Arrays;

/**
 * A data structure for storing structure constants for exceptional groups.
 * This implementation uses an int[] to store the structure constants N(a,b)
 * for positive roots a,b such that a comes before b in a fixed ordering.
 * (The ordering is fixed by storing a list of the roots as part of 
 * the StructureConstantsMatrix object.)
 * 
 * 
 * @author Joe Pleso 
 * @author Joe Hundley
 * 
 */
final class StructureConstantsMatrix implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 126L;
    private final int[] matrix;
    private final int n;

     private final int[][] roots;
     
     /*The matrix of structure constants for one of our static Group objects will be initialized
      * in one of two ways.  
      * 
      * (1) by simply reading the data in from EGData, where it has been hard-coded,
      * (2) using the method EGData.gilkeySeitz() to implement the algorithm outlined
      * in P. Gilkey, G. Seitz, Some representations of exceptional Lie groups,
      * Geom. Dedicata 25 (1998) 407-416.	
      * 
      */

    /**
     * Create a new (empty) matrix for storing structure constants.
     * 
     * @param r an int[][] representing the set of roots 
     * @param size the size of the matrix to be created
     */
    public StructureConstantsMatrix(int[][] r, int size) {
        n = size;
         roots = r;
        matrix = new int[((n * (n - 1)) / 2)];
    }
    
    /**
     * Create a new  matrix for storing structure constants, and populate
     * with prescribed data.
     * 
     * @param r an int[][] representing the set of roots 
     * @param m an int[] with the prescribed data
     * @param size the size of the matrix to be created
     */
    public StructureConstantsMatrix( int[][] r, int[] m, int size) {
        roots = r;
        n = size;
        matrix = m;
        if (matrix == null)
    	throw new NullPointerException("Attempt to define null structure constants matrix.");
    }

    /**
     * Gets the structure constant N(alpha, beta)
     *  corresponding to a pair of roots (alpha, beta).
     * 
     * @param alpha the first root
     * @param beta the second root
     * @return the value of N(iRoot,jRoot)
     */
    public int get(int[] alpha, int[] beta) {
	// find the index of each root.
        int i = findIndex(alpha);
        int j = findIndex(beta);
        
        // if the desired entry is below the diagonal use skew symmetry.
        if (j < i)
    		return (-1 * get(beta, alpha));
        
        //if not, we need to do a little arithmetic to determine which entry in the
        // actual one dimensional array corresponds to the (i,j) entry of the 
        // conceptual two dimensional array. 
        i++;
        j++;

        return matrix[((((2 * n) - i) * (i - 1)) / 2) - i + j - 1];
    }

    /**
     * Set the value at position i,j to x.
     * 
     * @param i  the row to be set
     * @param j  the column to be set
     * @param x  the new value for this position
     */
    public void set(int i, int j, int x) {
	// we only store above-diagonal entries.  those below the diagonal are handled by skew-symmetry.
        if (j < i)
    	set(j, i, (-1 * x));
        else {
            // we need to do a little arithmetic to determine which entry of the actual 
            // one dimensional array corresponds to the (i,j) entry of the conceptual
            // two dimensional array.
    	i++;
    	j++;
    	matrix[((((2 * n) - i) * (i - 1)) / 2) - i + j - 1] = x;
        }
    }

    
    /**
     * Finds the index of root in the int[][] roots
     * 
     * @param roots
     *            a int[][] to search in
     * @param root
     *            a int[] to find in roots
     * @return the index such that roots[index]==root is true, or -1 if a match
     *         was not found
     */
    private int findIndex(int[][] roots, int[] root) {
	for (int i = 0; i < roots.length; i++)
	    if (Arrays.equals(root, roots[i]))
		return i;
	return -1;
    }

    private int findIndex(int[] root) {
	return findIndex(roots, root);
    }

    
}